package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strconv"
)

// homeHandler 处理主页请求
func homeHandler(w http.ResponseWriter, r *http.Request) {
	// 加载应用列表
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 加载前端应用列表
	frontends, err := LoadFrontends("config.json")
	if err != nil {
		log.Printf("Failed to load frontends: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load frontends: %v", err), http.StatusInternalServerError)
		return
	}

	// 渲染模板
	tmpl := `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>应用管理控制台</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #3b82f6;
            --primary-light: #60a5fa;
            --primary-dark: #1e40af;
            --secondary-color: #06b6d4;
            --secondary-dark: #0891b2;
            --success-color: #10b981;
            --success-dark: #059669;
            --warning-color: #f59e0b;
            --warning-dark: #d97706;
            --danger-color: #ef4444;
            --danger-dark: #dc2626;
            --info-color: #0ea5e9;
            --info-dark: #0284c7;
            --light-color: #f8fafc;
            --light-secondary: #f1f5f9;
            --dark-color: #1e293b;
            --dark-light: #334155;
            --gray-color: #64748b;
            --gray-100: #f1f5f9;
            --gray-200: #e2e8f0;
            --gray-300: #cbd5e1;
            --border-color: #e2e8f0;
            --card-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
            --card-shadow-hover: 0 8px 16px rgba(15, 23, 42, 0.12);
            --input-border-focus: 0 0 0 3px rgba(59, 130, 246, 0.1);
            --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
            background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
            color: var(--dark-color);
            line-height: 1.6;
            font-size: 14px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        
        header {
            background: linear-gradient(135deg, var(--primary-color) 0%, var(--info-color) 100%);
            color: white;
            padding: 24px 0;
            box-shadow: var(--card-shadow);
            margin-bottom: 32px;
            border-radius: 0;
            backdrop-filter: blur(10px);
        }
        
        .header-content {
            display: flex;
            justify-content: space-between;
            align-items: center;
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 20px;
        }
        
        .logo {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        
        .logo i {
            font-size: 2.2rem;
            animation: slideIn 0.6s cubic-bezier(0.4, 0, 0.2, 1);
        }
        
        .logo h1 {
            font-size: 1.8rem;
            font-weight: 700;
            margin: 0;
            letter-spacing: -0.5px;
        }
        
        .subtitle {
            font-size: 0.95rem;
            opacity: 0.95;
            margin-top: 2px;
            font-weight: 400;
        }
        
        .dashboard-stats {
            display: flex;
            gap: 20px;
            margin-bottom: 30px;
            flex-wrap: wrap;
        }
        
        .stat-card {
            background: white;
            border-radius: 12px;
            padding: 24px;
            flex: 1;
            min-width: 200px;
            box-shadow: var(--card-shadow);
            transition: var(--transition);
            display: flex;
            align-items: center;
            gap: 16px;
            border: 1px solid var(--gray-200);
            position: relative;
            overflow: hidden;
        }
        
        .stat-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
            background: linear-gradient(90deg, var(--primary-color), var(--info-color));
            transform: translateX(-100%);
            transition: var(--transition);
        }
        
        .stat-card:hover {
            transform: translateY(-4px);
            box-shadow: var(--card-shadow-hover);
            border-color: var(--primary-light);
        }
        
        .stat-card:hover::before {
            transform: translateX(0);
        }
        
        .stat-icon {
            width: 56px;
            height: 56px;
            border-radius: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.5rem;
            flex-shrink: 0;
        }
        
        .stat-info h3 {
            font-size: 1.8rem;
            margin-bottom: 4px;
            color: var(--dark-color);
            font-weight: 700;
        }
        
        .stat-info p {
            color: var(--gray-color);
            font-size: 0.9rem;
            margin: 0;
        }
        
        .operations-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(550px, 1fr));
            gap: 25px;
            margin-bottom: 30px;
        }
        
        .operations-grid.upper {
            grid-template-columns: repeat(2, 1fr);
        }
        
        .operations-grid.lower {
            grid-template-columns: repeat(2, 1fr);
        }
        
        @media (max-width: 1000px) {
            .operations-grid.upper,
            .operations-grid.lower {
                grid-template-columns: 1fr;
            }
        }
        
        @media (max-width: 768px) {
            .operations-grid {
                grid-template-columns: 1fr;
            }
        }
        
        .operation-card {
            background: white;
            border-radius: 12px;
            padding: 28px;
            box-shadow: var(--card-shadow);
            transition: var(--transition);
            display: flex;
            flex-direction: column;
            border: 1px solid var(--gray-200);
            position: relative;
            overflow: hidden;
        }
        
        .operation-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
            background: linear-gradient(90deg, var(--primary-color), var(--info-color));
            transform: translateX(-100%);
            transition: var(--transition);
        }
        
        .operation-card:hover::before {
            transform: translateX(0);
        }
        
        .operation-card .form-group {
            flex: 1;
        }
        
        .operation-card:hover {
            transform: translateY(-4px);
            box-shadow: var(--card-shadow-hover);
            border-color: var(--primary-light);
        }
        
        .card-header {
            display: flex;
            align-items: center;
            gap: 12px;
            margin-bottom: 24px;
            padding-bottom: 0;
            border-bottom: none;
        }
        
        .card-header i {
            font-size: 1.5rem;
            color: white;
            background: linear-gradient(135deg, var(--primary-color), var(--info-color));
            padding: 10px 12px;
            border-radius: 8px;
            width: 40px;
            height: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-shrink: 0;
        }
        
        .card-header h2 {
            font-size: 1.3rem;
            font-weight: 600;
            color: var(--dark-color);
            margin: 0;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: var(--dark-color);
            font-size: 0.95rem;
        }
        
        select, input[type="file"], input[type="text"], input[type="number"] {
            width: 100%;
            padding: 10px 14px;
            border: 1px solid var(--border-color);
            border-radius: 8px;
            font-size: 0.95rem;
            transition: var(--transition);
            font-family: inherit;
            background-color: white;
        }
        
        select:hover, input[type="file"]:hover, input[type="text"]:hover, input[type="number"]:hover {
            border-color: var(--gray-300);
            background-color: var(--gray-100);
        }
        
        select:focus, input[type="file"]:focus, input[type="text"]:focus, input[type="number"]:focus {
            outline: none;
            border-color: var(--primary-color);
            box-shadow: var(--input-border-focus);
            background-color: white;
        }
        
        input[type="file"] {
            padding: 10px 15px;
        }
        
        input[type="submit"], input[type="button"], button, .btn {
            background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 0.95rem;
            font-weight: 500;
            transition: var(--transition);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            text-decoration: none;
            white-space: nowrap;
        }
        
        input[type="submit"]:hover, input[type="button"]:hover, button:hover, .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
        }
        
        input[type="submit"]:active, input[type="button"]:active, button:active, .btn:active {
            transform: translateY(0);
        }
        
        .btn-primary {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
        }
        
        .btn-primary:hover {
            box-shadow: 0 4px 12px rgba(67, 97, 238, 0.3);
        }
        
        .btn-success {
            background: linear-gradient(135deg, var(--success-color), var(--success-dark));
        }
        
        .btn-success:hover {
            box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
        }
        
        .btn-warning {
            background: linear-gradient(135deg, var(--warning-color), var(--warning-dark));
        }
        
        .btn-warning:hover {
            box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
        }
        
        .btn-info {
            background: linear-gradient(135deg, var(--info-color), var(--info-dark));
        }
        
        .btn-info:hover {
            box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3);
        }
        
        .btn-danger {
            background: linear-gradient(135deg, var(--danger-color), var(--danger-dark));
        }
        
        .btn-danger:hover {
            box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
        }
        
        .progress-container {
            display: none;
            margin-top: 20px;
            background: var(--light-secondary);
            border-radius: 8px;
            padding: 16px;
            border: 1px solid var(--border-color);
        }
        
        .progress-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
        }
        
        .progress-bar {
            width: 100%;
            height: 8px;
            background-color: var(--gray-200);
            border-radius: 4px;
            overflow: hidden;
        }
        
        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, var(--primary-color), var(--info-color));
            width: 0%;
            transition: width 0.3s ease;
            border-radius: 4px;
        }
        
        .progress-text {
            font-size: 0.9rem;
            color: var(--gray-color);
        }
        
        .log-content {
            background-color: #1e1e2e;
            color: #a9dc76;
            padding: 15px;
            border-radius: 8px;
            font-family: 'Courier New', monospace;
            white-space: pre-wrap;
            min-height: 700px;
            max-height: 700px;
            overflow-y: auto;
            margin-top: 15px;
            display: none;
            font-size: 0.9rem;
            line-height: 1.5;
        }
        
        /* 日志弹窗样式 */
        .log-modal-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.6);
            z-index: 5000;
            animation: fadeIn 0.3s;
        }
        
        .log-modal {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            border-radius: 12px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            z-index: 5001;
            width: 90%;
            max-width: 1200px;
            height: 85vh;
            display: none;
            flex-direction: column;
            animation: slideDown 0.3s;
        }
        
        .log-modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            border-bottom: 1px solid var(--border-color);
            background: linear-gradient(135deg, var(--primary-color), var(--info-color));
            color: white;
            border-radius: 12px 12px 0 0;
        }
        
        .log-modal-header h2 {
            margin: 0;
            font-size: 1.5rem;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .log-modal-header i {
            font-size: 1.3rem;
        }
        
        .log-modal-close {
            background: rgba(255, 255, 255, 0.2);
            border: none;
            color: white;
            font-size: 1.5rem;
            cursor: pointer;
            padding: 5px 10px;
            border-radius: 5px;
            transition: all 0.3s;
        }
        
        .log-modal-close:hover {
            background: rgba(255, 255, 255, 0.4);
            transform: rotate(90deg);
        }
        
        .log-modal-content {
            flex: 1;
            overflow-y: auto;
            padding: 20px 25px;
            background: #f8f9fa;
        }
        
        .log-modal-text {
            background-color: #1e1e2e;
            color: #a9dc76;
            padding: 20px;
            border-radius: 8px;
            font-family: 'Courier New', monospace;
            white-space: pre-wrap;
            word-wrap: break-word;
            font-size: 0.85rem;
            line-height: 1.6;
            border: 1px solid #2d2d44;
        }
        
        .log-modal-footer {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
            padding: 15px 25px;
            border-top: 1px solid var(--border-color);
            background: #f8f9fa;
            border-radius: 0 0 12px 12px;
        }
        
        .log-modal-btn {
            padding: 10px 20px;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.95rem;
            font-weight: 500;
            transition: all 0.3s;
        }
        
        .log-modal-btn-primary {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            color: white;
        }
        
        .log-modal-btn-primary:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(67, 97, 238, 0.3);
        }
        
        .log-modal-btn-danger {
            background: #e0e0e0;
            color: #333;
        }
        
        .log-modal-btn-danger:hover {
            background: #d0d0d0;
            transform: translateY(-2px);
        }
        
        footer {
            text-align: center;
            padding: 24px;
            color: var(--gray-color);
            font-size: 0.9rem;
            margin-top: 40px;
            border-top: 1px solid var(--border-color);
        }
        
        .section-divider {
            height: 1px;
            background: linear-gradient(to right, transparent, var(--border-color), transparent);
            margin: 40px 0;
        }
        
        .notification {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 16px 20px;
            border-radius: 8px;
            color: white;
            font-weight: 500;
            font-size: 0.95rem;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
            transform: translateX(400px);
            transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            z-index: 1000;
        }
        
        .notification.show {
            transform: translateX(0);
        }
        
        .notification.success {
            background: linear-gradient(135deg, var(--success-color), var(--success-dark));
        }
        
        .notification.error {
            background: linear-gradient(135deg, var(--danger-color), var(--danger-dark));
        }
        
        /* 自定义确认弹窗样式 */
        .custom-confirm-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 10000;
            animation: fadeIn 0.3s;
        }
        
        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }
        
        .custom-confirm-box {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: white;
            border-radius: 12px;
            box-shadow: 0 20px 40px rgba(15, 23, 42, 0.15);
            padding: 32px;
            min-width: 400px;
            max-width: 500px;
            animation: slideDown 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            z-index: 10001;
        }
        
        @keyframes slideDown {
            from {
                opacity: 0;
                transform: translate(-50%, -60%);
            }
            to {
                opacity: 1;
                transform: translate(-50%, -50%);
            }
        }
        
        .confirm-icon {
            font-size: 3rem;
            text-align: center;
            margin-bottom: 20px;
        }
        
        .confirm-icon.warning {
            color: #ff9800;
        }
        
        .confirm-icon.danger {
            color: #f44336;
        }
        
        .confirm-title {
            font-size: 1.5rem;
            font-weight: 600;
            text-align: center;
            margin-bottom: 15px;
            color: var(--dark-color);
        }
        
        .confirm-message {
            text-align: center;
            color: var(--gray-color);
            margin-bottom: 25px;
            line-height: 1.6;
        }
        
        .confirm-buttons {
            display: flex;
            gap: 15px;
            justify-content: center;
        }
        
        .confirm-btn {
            padding: 12px 30px;
            border: none;
            border-radius: 25px;
            font-size: 1rem;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s;
            min-width: 100px;
        }
        
        .confirm-btn-yes {
            background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
            color: white;
        }
        
        .confirm-btn-yes:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(59, 130, 246, 0.4);
        }
        
        .confirm-btn-no {
            background: #e0e0e0;
            color: #666;
        }
        
        .confirm-btn-no:hover {
            background: #d0d0d0;
            transform: translateY(-2px);
        }
    </style>
</head>
<body>
    <header>
        <div class="header-content">
            <div class="logo">
                <i class="fas fa-server"></i>
                <div>
                    <h1>应用管理控制台</h1>
                    <div class="subtitle">统一管理您的应用程序和服务</div>
                </div>
            </div>
        </div>
    </header>
    
    <div class="container">
        <div class="dashboard-stats">
            <div class="stat-card">
                <div class="stat-icon" style="background-color: rgba(67, 97, 238, 0.1); color: var(--primary-color);">
                    <i class="fas fa-cube"></i>
                </div>
                <div class="stat-info">
                    <h3>{{len .Applications}}</h3>
                    <p>后端应用总数</p>
                </div>
            </div>
            
            <div class="stat-card">
                <div class="stat-icon" style="background-color: rgba(76, 201, 240, 0.1); color: var(--success-color);">
                    <i class="fas fa-window-maximize"></i>
                </div>
                <div class="stat-info">
                    <h3>{{len .Frontends}}</h3>
                    <p>前端应用</p>
                </div>
            </div>
            
            <div class="stat-card">
                <div class="stat-icon" style="background-color: rgba(248, 150, 30, 0.1); color: var(--warning-color);">
                    <i class="fas fa-upload"></i>
                </div>
                <div class="stat-info">
                    <h3>6</h3>
                    <p>操作类型</p>
                </div>
            </div>
            
            <div class="stat-card">
                <div class="stat-icon" style="background-color: rgba(72, 149, 239, 0.1); color: var(--info-color);">
                    <i class="fas fa-sync-alt"></i>
                </div>
                <div class="stat-info">
                    <h3>2</h3>
                    <p>服务管理</p>
                </div>
            </div>
        </div>
        
        <div class="operations-grid upper">
            <!-- 上传普通文件部分 -->
            <div class="operation-card">
                <div class="card-header">
                    <i class="fas fa-file-upload"></i>
                    <h2>1. 上传文件</h2>
                </div>
                <form id="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
                    <div class="form-group">
                        <label for="uploadfile"><i class="fas fa-file"></i> 选择文件:</label>
                        <input type="file" name="uploadfile" id="uploadfile" required>
                    </div>
                    <input type="submit" value="上传文件" id="uploadBtn">
                    <div id="progressContainer1" class="progress-container">
                        <div class="progress-header">
                            <span>上传进度</span>
                            <span id="progressText1" class="progress-text">0%</span>
                        </div>
                        <div class="progress-bar">
                            <div id="progressFill1" class="progress-fill"></div>
                        </div>
                    </div>
                </form>
            </div>
            
            <!-- 上传Jar文件并更新应用部分 -->
            <div class="operation-card">
                <div class="card-header">
                    <i class="fas fa-cloud-upload-alt"></i>
                    <h2>2. 上传Jar文件并更新应用</h2>
                </div>
                <form id="uploadJarForm" action="/uploadJar" method="post" enctype="multipart/form-data">
                    <div class="form-group">
                        <label for="jarfile"><i class="fas fa-archive"></i> 选择Jar文件:</label>
                        <input type="file" name="jarfile" id="jarfile" required accept=".jar">
                    </div>
                    <div class="form-group">
                        <label for="jarport"><i class="fas fa-plug"></i> 选择服务端口:</label>
                        <select name="jarport" id="jarport" required>
                            <option value="">--请选择应用--</option>
                            {{range .Applications}}
                            <option value="{{.Port}}">{{.Port}} - {{.JarName}}</option>
                            {{end}}
                        </select>
                    </div>
                    <input type="submit" value="上传并更新" id="uploadJarBtn" class="btn-success">
                    <div id="progressContainer2" class="progress-container">
                        <div class="progress-header">
                            <span>上传进度</span>
                            <span id="progressText2" class="progress-text">0%</span>
                        </div>
                        <div class="progress-bar">
                            <div id="progressFill2" class="progress-fill"></div>
                        </div>
                    </div>
                </form>
            </div>
        </div>
        
        <div style="margin-bottom: 40px;"></div>
        
        <div class="operations-grid lower">
            <div class="operation-card">
                <div class="card-header">
                    <i class="fas fa-code"></i>
                    <h2>3. 上传前端代码</h2>
                </div>
                <form id="uploadFrontendForm" action="/uploadFrontend" method="post" enctype="multipart/form-data">
                    <div class="form-group">
                        <label for="frontendfile"><i class="fas fa-file-archive"></i> 选择前端Zip文件:</label>
                        <input type="file" name="frontendfile" id="frontendfile" required accept=".zip">
                    </div>
                    <div class="form-group">
                        <label for="frontendName"><i class="fas fa-window-restore"></i> 选择前端应用:</label>
                        <select name="frontendName" id="frontendName" required>
                            <option value="">--请选择前端应用--</option>
                            {{range .Frontends}}
                            <option value="{{.Name}}">{{.Name}} - {{.Path}}</option>
                            {{end}}
                        </select>
                    </div>
                    <input type="submit" value="上传前端代码" id="uploadFrontendBtn" class="btn-info">
                    <div id="progressContainer3" class="progress-container">
                        <div class="progress-header">
                            <span>上传进度</span>
                            <span id="progressText3" class="progress-text">0%</span>
                        </div>
                        <div class="progress-bar">
                            <div id="progressFill3" class="progress-fill"></div>
                        </div>
                    </div>
                </form>
            </div>
            
            <div class="operation-card">
                <div class="card-header">
                    <i class="fas fa-file-alt"></i>
                    <h2>4. 查看应用日志</h2>
                </div>
                <form id="viewLogForm" action="/viewLog" method="get">
                    <div class="form-group">
                        <label for="logPort"><i class="fas fa-terminal"></i> 选择应用端口:</label>
                        <select name="port" id="logPort" required>
                            <option value="">--请选择应用--</option>
                            {{range .Applications}}
                            <option value="{{.Port}}">{{.Port}} - {{.JarName}}</option>
                            {{end}}
                        </select>
                    </div>
                    <div class="form-group">
                        <label for="logLines"><i class="fas fa-list-ol"></i> 显示行数:</label>
                        <select name="lines" id="logLines">
                            <option value="50">50行</option>
                            <option value="100" selected>100行</option>
                            <option value="200">200行</option>
                            <option value="500">500行</option>
                            <option value="1000">1000行</option>
                            <option value="2000">2000行</option>
                        </select>
                    </div>
                    <div style="display: flex; gap: 10px; margin-bottom: 15px;">
                        <input type="submit" value="查看日志">
                        <input type="button" value="下载日志" id="downloadLogBtn" class="btn-danger" onclick="downloadLog()">
                        <input type="button" value="清空日志" id="clearLogBtn" class="btn-warning" onclick="clearLog()">
                    </div>
                    <div id="logContent" class="log-content"></div>
                </form>
            </div>
        </div>
        
        <div class="section-divider"></div>
        
        <div class="operations-grid lower">
            <div class="operation-card">
                <div class="card-header">
                    <i class="fas fa-network-wired"></i>
                    <h2>5. 应用服务管理</h2>
                </div>
                <p style="margin-bottom: 15px; color: var(--gray-color);">
                    <i class="fas fa-info-circle"></i> 停止、启动或重启应用服务
                </p>
                <div style="display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 20px;">
                    <div style="flex: 1; min-width: 200px;">
                        <label style="display: block; margin-bottom: 8px; font-weight: 500;"><i class="fas fa-server"></i> 选择应用：</label>
                        <select id="appControlPort" style="width: 100%; padding: 10px; border: 1px solid var(--border-color); border-radius: 8px;">
                            <option value="">--请选择应用--</option>
                            {{range .Applications}}
                            <option value="{{.Port}}">{{.Port}} - {{.JarName}}</option>
                            {{end}}
                        </select>
                    </div>
                    <div style="display: flex; gap: 10px; align-items: flex-end;">
                        <button type="button" class="btn btn-warning" onclick="stopApplication()">
                            <i class="fas fa-stop-circle"></i> 停止应用
                        </button>
                        <button type="button" class="btn btn-success" onclick="startApplication()">
                            <i class="fas fa-play-circle"></i> 启动应用
                        </button>
                        <button type="button" class="btn btn-info" onclick="restartApplication()">
                            <i class="fas fa-sync-alt"></i> 重启应用
                        </button>
                    </div>
                </div>
            </div>
            
            <div class="operation-card">
                <div class="card-header">
                    <i class="fas fa-cogs"></i>
                    <h2>6. Nginx 管理</h2>
                </div>
                <p style="margin-bottom: 15px; color: var(--gray-color);">
                    <i class="fas fa-info-circle"></i> 管理 Nginx 配置文件和服务
                </p>
                <div style="display: flex; gap: 10px; flex-wrap: wrap;">
                    <button type="button" class="btn btn-primary" onclick="showNginxConfigLogin()">
                        <i class="fas fa-cog"></i> 配置管理
                    </button>
                    <button type="button" class="btn btn-warning" onclick="confirmReloadNginx()">
                        <i class="fas fa-sync"></i> 重载 Nginx
                    </button>
                    <button type="button" class="btn btn-danger" onclick="confirmRestartNginx()">
                        <i class="fas fa-power-off"></i> 重启 Nginx
                    </button>
                </div>
            </div>
        </div>
    </div>
    
    <footer>
        <p>应用管理控制台 &copy; 2025 | 统一应用管理平台</p>
    </footer>
    
    <div id="notification" class="notification"></div>
    
    <!-- 日志弹窗 -->
    <div id="logModalOverlay" class="log-modal-overlay">
        <div class="log-modal">
            <div class="log-modal-header">
                <h2>
                    <i class="fas fa-file-alt"></i>
                    <span>应用日志</span>
                </h2>
                <button class="log-modal-close" onclick="closeLogModal()">&times;</button>
            </div>
            <div class="log-modal-content">
                <div id="logModalText" class="log-modal-text"></div>
            </div>
            <div class="log-modal-footer">
                <button class="log-modal-btn log-modal-btn-primary" onclick="downloadLogFromModal()">
                    <i class="fas fa-download"></i> 下载日志
                </button>
                <button class="log-modal-btn log-modal-btn-danger" onclick="closeLogModal()">
                    关闭window
                </button>
            </div>
        </div>
    </div>
    
    <!-- 自定义确认弹窗 -->
    <div id="customConfirmOverlay" class="custom-confirm-overlay">
        <div class="custom-confirm-box">
            <div id="confirmIcon" class="confirm-icon"></div>
            <div id="confirmTitle" class="confirm-title"></div>
            <div id="confirmMessage" class="confirm-message"></div>
            <div class="confirm-buttons">
                <button id="confirmYes" class="confirm-btn confirm-btn-yes">确定</button>
                <button id="confirmNo" class="confirm-btn confirm-btn-no">取消</button>
            </div>
        </div>
    </div>
    
    <!-- Nginx 配置管理密码弹窗 -->
    <div id="nginxPasswordOverlay" class="custom-confirm-overlay">
        <div class="custom-confirm-box">
            <div class="confirm-icon">
                <i class="fas fa-lock" style="color: var(--primary-color);"></i>
            </div>
            <div class="confirm-title">Nginx 配置管理</div>
            <div class="confirm-message">请输入管理员密码以继续</div>
            <div style="margin: 20px 0;">
                <input type="password" id="nginxPassword" placeholder="请输入密码" 
                       style="width: 100%; padding: 12px; border: 1px solid var(--border-color); border-radius: 8px; font-size: 1rem;"
                       onkeypress="if(event.keyCode==13) submitNginxPassword()">
                <div id="passwordError" style="color: var(--danger-color); margin-top: 10px; display: none;">
                    <i class="fas fa-exclamation-circle"></i> 密码错误，请重试
                </div>
            </div>
            <div class="confirm-buttons">
                <button onclick="submitNginxPassword()" class="confirm-btn confirm-btn-yes">登录</button>
                <button onclick="closeNginxPasswordDialog()" class="confirm-btn confirm-btn-no">取消</button>
            </div>
        </div>
    </div>
    
    <script>
        // 显示通知函数
        function showNotification(message, isSuccess) {
            const notification = document.getElementById('notification');
            notification.textContent = message;
            notification.className = 'notification ' + (isSuccess ? 'success' : 'error');
            notification.classList.add('show');
            
            setTimeout(() => {
                notification.classList.remove('show');
            }, 3000);
        }
        
        // 自定义确认弹窗
        function showCustomConfirm(title, message, iconType, onConfirm) {
            const overlay = document.getElementById('customConfirmOverlay');
            const icon = document.getElementById('confirmIcon');
            const titleEl = document.getElementById('confirmTitle');
            const messageEl = document.getElementById('confirmMessage');
            const yesBtn = document.getElementById('confirmYes');
            const noBtn = document.getElementById('confirmNo');
            
            // 设置内容
            titleEl.textContent = title;
            messageEl.textContent = message;
            
            // 设置图标
            if (iconType === 'warning') {
                icon.innerHTML = '<i class="fas fa-exclamation-triangle"></i>';
                icon.className = 'confirm-icon warning';
            } else if (iconType === 'danger') {
                icon.innerHTML = '<i class="fas fa-exclamation-circle"></i>';
                icon.className = 'confirm-icon danger';
            }
            
            // 显示弹窗
            overlay.style.display = 'block';
            
            // 处理确认
            yesBtn.onclick = function() {
                overlay.style.display = 'none';
                if (onConfirm) onConfirm();
            };
            
            // 处理取消
            noBtn.onclick = function() {
                overlay.style.display = 'none';
            };
            
            // 点击背景关闭
            overlay.onclick = function(e) {
                if (e.target === overlay) {
                    overlay.style.display = 'none';
                }
            };
        }
        
        // 确认重载 Nginx
        function confirmReloadNginx() {
            showCustomConfirm(
                '重载 Nginx 配置',
                '确定要重载 Nginx 配置吗？这将使新的配置生效。',
                'warning',
                function() {
                    // 提交表单
                    const form = document.createElement('form');
                    form.method = 'POST';
                    form.action = '/reloadNginx';
                    document.body.appendChild(form);
                    form.submit();
                }
            );
        }
        
        // 确认重启 Nginx
        function confirmRestartNginx() {
            showCustomConfirm(
                '重启 Nginx 服务',
                '确定要重启 Nginx 服务吗？此操作可能会短暂影响正在运行的服务。',
                'danger',
                function() {
                    // 提交表单
                    const form = document.createElement('form');
                    form.method = 'POST';
                    form.action = '/restartNginx';
                    document.body.appendChild(form);
                    form.submit();
                }
            );
        }
        
        // 停止应用
        function stopApplication() {
            const port = document.getElementById('appControlPort').value;
            if (!port) {
                showNotification('请选择应用', false);
                return;
            }
            
            showCustomConfirm(
                '停止应用',
                '确定要停止此应用吗？',
                'warning',
                function() {
                    const form = document.createElement('form');
                    form.method = 'POST';
                    form.action = '/stop';
                    const input = document.createElement('input');
                    input.type = 'hidden';
                    input.name = 'port';
                    input.value = port;
                    form.appendChild(input);
                    document.body.appendChild(form);
                    form.submit();
                }
            );
        }
        
        // 启动应用
        function startApplication() {
            const port = document.getElementById('appControlPort').value;
            if (!port) {
                showNotification('请选择应用', false);
                return;
            }
            
            showCustomConfirm(
                '启动应用',
                '确定要启动此应用吗？',
                'warning',
                function() {
                    const form = document.createElement('form');
                    form.method = 'POST';
                    form.action = '/start';
                    const input = document.createElement('input');
                    input.type = 'hidden';
                    input.name = 'port';
                    input.value = port;
                    form.appendChild(input);
                    document.body.appendChild(form);
                    form.submit();
                }
            );
        }
        
        // 重启应用
        function restartApplication() {
            const port = document.getElementById('appControlPort').value;
            if (!port) {
                showNotification('请选择应用', false);
                return;
            }
            
            showCustomConfirm(
                '重启应用',
                '确定要重启此应用吗？',
                'warning',
                function() {
                    const form = document.createElement('form');
                    form.method = 'POST';
                    form.action = '/restart';
                    const input = document.createElement('input');
                    input.type = 'hidden';
                    input.name = 'port';
                    input.value = port;
                    form.appendChild(input);
                    document.body.appendChild(form);
                    form.submit();
                }
            );
        }
        
        // 显示 Nginx 配置管理密码弹窗
        function showNginxConfigLogin() {
            const overlay = document.getElementById('nginxPasswordOverlay');
            const passwordInput = document.getElementById('nginxPassword');
            const errorDiv = document.getElementById('passwordError');
            
            // 重置输入
            passwordInput.value = '';
            errorDiv.style.display = 'none';
            
            // 显示弹窗
            overlay.style.display = 'block';
            
            // 自动聚焦到密码输入框
            setTimeout(() => passwordInput.focus(), 100);
        }
        
        // 关闭密码弹窗
        function closeNginxPasswordDialog() {
            document.getElementById('nginxPasswordOverlay').style.display = 'none';
        }
        
        // 提交密码
        function submitNginxPassword() {
            const password = document.getElementById('nginxPassword').value;
            const errorDiv = document.getElementById('passwordError');
            
            if (!password) {
                errorDiv.textContent = '请输入密码';
                errorDiv.style.display = 'block';
                return;
            }
            
            // 发送验证请求
            fetch('/nginxConfig/login', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },
                body: 'password=' + encodeURIComponent(password)
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    // 登录成功，跳转到配置管理页面
                    window.location.href = '/nginxConfig';
                } else {
                    // 密码错误
                    errorDiv.innerHTML = '<i class="fas fa-exclamation-circle"></i> ' + (data.error || '密码错误，请重试');
                    errorDiv.style.display = 'block';
                    document.getElementById('nginxPassword').value = '';
                    document.getElementById('nginxPassword').focus();
                }
            })
            .catch(error => {
                errorDiv.innerHTML = '<i class="fas fa-exclamation-circle"></i> 验证失败: ' + error;
                errorDiv.style.display = 'block';
            });
        }
        
        // 清空日志显示
        function clearLog() {
            document.getElementById('logContent').style.display = 'none';
            document.getElementById('logContent').textContent = '';
            showNotification('日志显示已清空', true);
        }
        
        // 打开日志弹窗
        function openLogModal(content) {
            const overlay = document.getElementById('logModalOverlay');
            const modal = document.querySelector('.log-modal');
            const logText = document.getElementById('logModalText');
            
            logText.textContent = content;
            overlay.style.display = 'block';
            modal.style.display = 'flex';
        }
        
        // 关闭日志弹窗
        function closeLogModal() {
            const overlay = document.getElementById('logModalOverlay');
            const modal = document.querySelector('.log-modal');
            
            overlay.style.display = 'none';
            modal.style.display = 'none';
        }
        
        // 从弹窗中下载日志
        function downloadLogFromModal() {
            const portSelect = document.getElementById('logPort');
            if (!portSelect.value) {
                showNotification('请选择应用端口', false);
                return;
            }
            
            const port = portSelect.value;
            window.open('/downloadLog?port=' + port, '_blank');
        }
        
        // 点击背景关闭弹窗
        document.getElementById('logModalOverlay').addEventListener('click', function(e) {
            if (e.target === this) {
                closeLogModal();
            }
        });
        
        // 处理普通文件上传进度
        document.getElementById('uploadForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const fileInput = document.getElementById('uploadfile');
            if (!fileInput.files.length) {
                showNotification('请选择要上传的文件', false);
                return;
            }
            
            const file = fileInput.files[0];
            const formData = new FormData();
            formData.append('uploadfile', file);
            
            // 显示进度条
            document.getElementById('progressContainer1').style.display = 'block';
            const progressFill = document.getElementById('progressFill1');
            const progressText = document.getElementById('progressText1');
            
            // 禁用上传按钮
            const uploadBtn = document.getElementById('uploadBtn');
            uploadBtn.disabled = true;
            uploadBtn.value = '上传中...';
            
            const xhr = new XMLHttpRequest();
            
            // 监听上传进度
            xhr.upload.addEventListener('progress', function(e) {
                if (e.lengthComputable) {
                    const percentComplete = (e.loaded / e.total) * 100;
                    progressFill.style.width = percentComplete + '%';
                    progressText.textContent = Math.round(percentComplete) + '%';
                }
            });
            
            // 处理上传完成
            xhr.addEventListener('load', function() {
                if (xhr.status === 200) {
                    progressFill.style.width = '100%';
                    progressText.textContent = '100% - 上传完成';
                    showNotification('文件上传成功!', true);
                    
                    // 延迟跳转到结果页面
                    setTimeout(function() {
                        document.open();
                        document.write(xhr.responseText);
                        document.close();
                    }, 1500);
                } else {
                    showNotification('上传失败: ' + xhr.statusText, false);
                    // 重新启用上传按钮
                    uploadBtn.disabled = false;
                    uploadBtn.value = '上传文件';
                    document.getElementById('progressContainer1').style.display = 'none';
                }
            });
            
            // 处理上传错误
            xhr.addEventListener('error', function() {
                showNotification('上传过程中发生错误', false);
                // 重新启用上传按钮
                uploadBtn.disabled = false;
                uploadBtn.value = '上传文件';
                document.getElementById('progressContainer1').style.display = 'none';
            });
            
            // 发送请求
            xhr.open('POST', '/upload');
            xhr.send(formData);
        });
        
        // 处理Jar文件上传进度
        document.getElementById('uploadJarForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const fileInput = document.getElementById('jarfile');
            const portSelect = document.getElementById('jarport');
            
            if (!fileInput.files.length) {
                showNotification('请选择要上传的Jar文件', false);
                return;
            }
            
            if (!portSelect.value) {
                showNotification('请选择服务端口', false);
                return;
            }
            
            const file = fileInput.files[0];
            const formData = new FormData();
            formData.append('jarfile', file);
            formData.append('jarport', portSelect.value);
            
            // 显示进度条
            document.getElementById('progressContainer2').style.display = 'block';
            const progressFill = document.getElementById('progressFill2');
            const progressText = document.getElementById('progressText2');
            
            // 禁用上传按钮
            const uploadBtn = document.getElementById('uploadJarBtn');
            uploadBtn.disabled = true;
            uploadBtn.value = '上传中...';
            
            const xhr = new XMLHttpRequest();
            
            // 监听上传进度
            xhr.upload.addEventListener('progress', function(e) {
                if (e.lengthComputable) {
                    const percentComplete = (e.loaded / e.total) * 100;
                    progressFill.style.width = percentComplete + '%';
                    progressText.textContent = Math.round(percentComplete) + '%';
                }
            });
            
            // 处理上传完成
            xhr.addEventListener('load', function() {
                if (xhr.status === 200) {
                    progressFill.style.width = '100%';
                    progressText.textContent = '100% - 上传完成';
                    showNotification('Jar文件上传并更新成功!', true);
                    
                    // 延迟跳转到结果页面
                    setTimeout(function() {
                        document.open();
                        document.write(xhr.responseText);
                        document.close();
                    }, 1500);
                } else {
                    showNotification('上传失败: ' + xhr.statusText, false);
                    // 重新启用上传按钮
                    uploadBtn.disabled = false;
                    uploadBtn.value = '上传并更新';
                    document.getElementById('progressContainer2').style.display = 'none';
                }
            });
            
            // 处理上传错误
            xhr.addEventListener('error', function() {
                showNotification('上传过程中发生错误', false);
                // 重新启用上传按钮
                uploadBtn.disabled = false;
                uploadBtn.value = '上传并更新';
                document.getElementById('progressContainer2').style.display = 'none';
            });
            
            // 发送请求
            xhr.open('POST', '/uploadJar');
            xhr.send(formData);
        });
        
        // 处理前端文件上传进度
        document.getElementById('uploadFrontendForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const fileInput = document.getElementById('frontendfile');
            const nameSelect = document.getElementById('frontendName');
            
            if (!fileInput.files.length) {
                showNotification('请选择要上传的前端Zip文件', false);
                return;
            }
            
            if (!nameSelect.value) {
                showNotification('请选择前端应用', false);
                return;
            }
            
            const file = fileInput.files[0];
            const formData = new FormData();
            formData.append('frontendfile', file);
            formData.append('frontendName', nameSelect.value);
            
            // 显示进度条
            document.getElementById('progressContainer3').style.display = 'block';
            const progressFill = document.getElementById('progressFill3');
            const progressText = document.getElementById('progressText3');
            
            // 禁用上传按钮
            const uploadBtn = document.getElementById('uploadFrontendBtn');
            uploadBtn.disabled = true;
            uploadBtn.value = '上传中...';
            
            const xhr = new XMLHttpRequest();
            
            // 监听上传进度
            xhr.upload.addEventListener('progress', function(e) {
                if (e.lengthComputable) {
                    const percentComplete = (e.loaded / e.total) * 100;
                    progressFill.style.width = percentComplete + '%';
                    progressText.textContent = Math.round(percentComplete) + '%';
                }
            });
            
            // 处理上传完成
            xhr.addEventListener('load', function() {
                if (xhr.status === 200) {
                    progressFill.style.width = '100%';
                    progressText.textContent = '100% - 上传完成';
                    showNotification('前端代码上传成功!', true);
                    
                    // 延迟跳转到结果页面
                    setTimeout(function() {
                        document.open();
                        document.write(xhr.responseText);
                        document.close();
                    }, 1500);
                } else {
                    showNotification('上传失败: ' + xhr.statusText, false);
                    // 重新启用上传按钮
                    uploadBtn.disabled = false;
                    uploadBtn.value = '上传前端代码';
                    document.getElementById('progressContainer3').style.display = 'none';
                }
            });
            
            // 处理上传错误
            xhr.addEventListener('error', function() {
                showNotification('上传过程中发生错误', false);
                // 重新启用上传按钮
                uploadBtn.disabled = false;
                uploadBtn.value = '上传前端代码';
                document.getElementById('progressContainer3').style.display = 'none';
            });
            
            // 发送请求
            xhr.open('POST', '/uploadFrontend');
            xhr.send(formData);
        });
        
        // 处理日志查看
        document.getElementById('viewLogForm').addEventListener('submit', function(e) {
            e.preventDefault();
            
            const portSelect = document.getElementById('logPort');
            const linesSelect = document.getElementById('logLines');
            
            if (!portSelect.value) {
                showNotification('请选择应用端口', false);
                return;
            }
            
            const port = portSelect.value;
            const lines = linesSelect.value;
            
            const xhr = new XMLHttpRequest();
            xhr.open('GET', '/viewLog?port=' + port + '&lines=' + lines);
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        // 在弹窗中上载日志
                        openLogModal(xhr.responseText);
                        showNotification('日志加载成功', true);
                    } else {
                        showNotification('查看日志失败: ' + xhr.statusText, false);
                    }
                }
            };
            xhr.send();
        });
        
        // 下载日志(内联函数)
        function downloadLog() {
            downloadLogFromModal();
        }
    </script>
</body>
</html>`

	t, err := template.New("home").Parse(tmpl)
	if err != nil {
		log.Printf("Failed to parse template: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to parse template: %v", err), http.StatusInternalServerError)
		return
	}

	data := struct {
		Applications []Application
		Frontends    []Front
	}{
		Applications: apps,
		Frontends:    frontends,
	}

	err = t.Execute(w, data)
	if err != nil {
		log.Printf("Failed to execute template: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to execute template: %v", err), http.StatusInternalServerError)
		return
	}
}

// updateHandler 处理应用更新请求
func updateHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("port")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 执行更新操作
	err = UpdateApplication(app, "")
	if err != nil {
		log.Printf("Failed to update application: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to update application: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>更新成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">应用更新成功!</h1>
		<p>应用 "%s" (端口 %d) 已成功更新。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`, app.JarName, app.Port)
}

// uploadHandler 处理文件上传请求
func uploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 处理文件上传
	_, err := handleFileUploadWithProgress(w, r)
	if err != nil {
		log.Printf("Failed to upload file: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to upload file: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>上传成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">文件上传成功!</h1>
		<p>文件已成功上传到服务器。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`)
}

// uploadJarHandler 处理Jar文件上传和应用更新请求
func uploadJarHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("jarport")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	// 处理Jar文件上传
	uploadedFilePath, err := handleJarUploadWithProgress(w, r)
	if err != nil {
		log.Printf("Failed to upload jar file: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to upload jar file: %v", err), http.StatusInternalServerError)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 这里应该获取上传的文件路径并执行更新
	// 在实际应用中，你需要从前端获取文件名或从上传处理函数中获取完整路径
	// uploadedFilePath已经从handleJarUploadWithProgress函数中获取

	// 执行更新操作
	err = UpdateApplication(app, uploadedFilePath)
	if err != nil {
		log.Printf("Failed to update application: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to update application: %v", err), http.StatusInternalServerError)
		return
	}

	// 删除上传的jar文件
	// os.Remove(uploadedFilePath)  // 可选：更新完成后删除上传的jar文件

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>更新成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">应用更新成功!</h1>
		<p>Jar文件已成功上传，并且应用 "%s" (端口 %d) 已更新。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`, app.JarName, app.Port)
}

// stopHandler 处理停止应用请求
func stopHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("port")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 执行停止操作
	err = StopApplication(app)
	if err != nil {
		log.Printf("Failed to stop application: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to stop application: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>停止成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">应用停止成功!</h1>
		<p>应用 "%s" (端口 %d) 已成功停止。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`, app.JarName, app.Port)
}

// startHandler 处理启动应用请求
func startHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("port")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 执行启动操作
	err = StartApplication(app)
	if err != nil {
		log.Printf("Failed to start application: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to start application: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>启动成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">应用启动成功!</h1>
		<p>应用 "%s" (端口 %d) 已成功启动。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`, app.JarName, app.Port)
}

// ... existing code ...
func restartHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("port")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 执行重启操作
	err = RestartApplication(app)
	if err != nil {
		log.Printf("Failed to restart application: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to restart application: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>重启成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">应用重启成功!</h1>
		<p>应用 "%s" (端口 %d) 已成功重启。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`, app.JarName, app.Port)
}

// uploadFrontendHandler 处理前端文件上传请求
func uploadFrontendHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取前端应用信息
	frontendName := r.FormValue("frontendName")

	if frontendName == "" {
		http.Error(w, "Frontend name is required", http.StatusBadRequest)
		return
	}

	// 处理前端文件上传
	uploadedFilePath, err := handleFrontendUploadWithProgress(w, r)
	if err != nil {
		log.Printf("Failed to upload frontend file: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to upload frontend file: %v", err), http.StatusInternalServerError)
		return
	}

	// 加载前端配置
	frontends, err := LoadFrontends("config.json")
	if err != nil {
		log.Printf("Failed to load frontends: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load frontends: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的前端应用
	front := FindFrontendByName(frontends, frontendName)
	if front == nil {
		errMsg := fmt.Sprintf("Frontend with name %s not found", frontendName)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 执行前端上传操作
	err = UploadFrontend(front, uploadedFilePath)
	if err != nil {
		log.Printf("Failed to upload frontend: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to upload frontend: %v", err), http.StatusInternalServerError)
		return
	}

	// 删除上传的zip文件
	os.Remove(uploadedFilePath)

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
	<!DOCTYPE html>
	<html>
	<head>
		<title>上传成功</title>
		<meta charset="UTF-8">
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.success { color: green; }
			a { color: #007bff; text-decoration: none; }
			a:hover { text-decoration: underline; }
		</style>
	</head>
	<body>
		<h1 class="success">前端代码上传成功!</h1>
		<p>前端应用 "%s" 已成功上传到 "%s"。</p>
		<a href="/">返回主页</a>
	</body>
	</html>
	`, front.Name, front.Path)
}

// restartNginxHandler 处理Nginx重启请求
func restartNginxHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 执行Nginx重启操作（新方式）
	err := RestartNginxNew()
	if err != nil {
		log.Printf("Failed to restart nginx: %v\n", err)
		// 返回错误响应
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		fmt.Fprintf(w, `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>重启失败</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%%, #764ba2 100%%);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            padding: 20px;
        }
        .container {
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
            padding: 40px;
            max-width: 600px;
            text-align: center;
            animation: slideIn 0.5s ease-out;
        }
        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        .icon {
            font-size: 4rem;
            color: #f72585;
            margin-bottom: 20px;
            animation: shake 0.5s;
        }
        @keyframes shake {
            0%%, 100%% { transform: translateX(0); }
            25%% { transform: translateX(-10px); }
            75%% { transform: translateX(10px); }
        }
        h1 {
            color: #f72585;
            font-size: 2rem;
            margin-bottom: 15px;
        }
        .message {
            color: #6c757d;
            font-size: 1.1rem;
            margin-bottom: 10px;
            line-height: 1.6;
        }
        .error-detail {
            background: #fff3cd;
            border: 1px solid #ffc107;
            border-radius: 8px;
            padding: 15px;
            margin: 20px 0;
            color: #856404;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            text-align: left;
            word-break: break-all;
        }
        .btn {
            display: inline-block;
            padding: 12px 30px;
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            text-decoration: none;
            border-radius: 25px;
            font-weight: 500;
            margin-top: 20px;
            transition: all 0.3s;
            border: none;
            cursor: pointer;
            font-size: 1rem;
        }
        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">
            <i class="fas fa-exclamation-triangle"></i>
        </div>
        <h1>Nginx 重启失败</h1>
        <p class="message">重启 Nginx 服务时发生错误</p>
        <div class="error-detail">
            <strong>错误信息：</strong><br>%s
        </div>
        <p class="message">请检查 Nginx 配置文件和服务状态，然后重试。</p>
        <a href="/" class="btn">
            <i class="fas fa-home"></i> 返回主页
        </a>
    </div>
</body>
</html>
`, err.Error())
		return
	}

	// 返回成功响应
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>重启成功</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%%, #764ba2 100%%);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 0;
            padding: 20px;
        }
        .container {
            background: white;
            border-radius: 15px;
            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
            padding: 40px;
            max-width: 600px;
            text-align: center;
            animation: slideIn 0.5s ease-out;
        }
        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        .icon {
            font-size: 4rem;
            color: #4CAF50;
            margin-bottom: 20px;
            animation: bounce 1s;
        }
        @keyframes bounce {
            0%%, 20%%, 50%%, 80%%, 100%% { transform: translateY(0); }
            40%% { transform: translateY(-20px); }
            60%% { transform: translateY(-10px); }
        }
        h1 {
            color: #4CAF50;
            font-size: 2rem;
            margin-bottom: 15px;
        }
        .message {
            color: #6c757d;
            font-size: 1.1rem;
            margin-bottom: 10px;
            line-height: 1.6;
        }
        .info-box {
            background: #d1ecf1;
            border: 1px solid #bee5eb;
            border-radius: 8px;
            padding: 15px;
            margin: 20px 0;
            color: #0c5460;
        }
        .btn-group {
            display: flex;
            gap: 15px;
            justify-content: center;
            margin-top: 30px;
            flex-wrap: wrap;
        }
        .btn {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            padding: 12px 30px;
            color: white;
            text-decoration: none;
            border-radius: 25px;
            font-weight: 500;
            transition: all 0.3s;
            border: none;
            cursor: pointer;
            font-size: 1rem;
        }
        .btn-primary {
            background: linear-gradient(135deg, #667eea, #764ba2);
        }
        .btn-primary:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
        }
        .btn-secondary {
            background: linear-gradient(135deg, #4CAF50, #2E7D32);
        }
        .btn-secondary:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(76, 175, 80, 0.4);
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">
            <i class="fas fa-check-circle"></i>
        </div>
        <h1>Nginx 重启成功！</h1>
        <p class="message">Nginx 服务已成功重启，所有配置已生效。</p>
        <div class="info-box">
            <i class="fas fa-info-circle"></i> Nginx 已完全重启，所有服务正常运行。
        </div>
        <div class="btn-group">
            <a href="/" class="btn btn-primary">
                <i class="fas fa-home"></i> 返回主页
            </a>
            <a href="/nginxConfig" class="btn btn-secondary">
                <i class="fas fa-cog"></i> 配置管理
            </a>
        </div>
    </div>
</body>
</html>
`)
}

// viewLogHandler 处理查看应用日志请求
func viewLogHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("port")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	// 获取行数
	linesStr := r.FormValue("lines")
	if linesStr == "" {
		linesStr = "100" // 默认显示100行
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	lines, err := strconv.Atoi(linesStr)
	if err != nil {
		log.Printf("Invalid lines number: %v\n", err)
		http.Error(w, "Invalid lines number", http.StatusBadRequest)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 获取日志内容
	logLines, err := TailApplicationLog(app, lines)
	if err != nil {
		log.Printf("Failed to read application log: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to read application log: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回日志内容
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	for _, line := range logLines {
		fmt.Fprintln(w, line)
	}
}

// downloadLogHandler 处理下载应用日志请求
func downloadLogHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// 获取端口号
	portStr := r.FormValue("port")
	if portStr == "" {
		http.Error(w, "Port is required", http.StatusBadRequest)
		return
	}

	port, err := strconv.Atoi(portStr)
	if err != nil {
		log.Printf("Invalid port number: %v\n", err)
		http.Error(w, "Invalid port number", http.StatusBadRequest)
		return
	}

	// 加载应用配置
	apps, err := LoadApplications("config.json")
	if err != nil {
		log.Printf("Failed to load applications: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to load applications: %v", err), http.StatusInternalServerError)
		return
	}

	// 查找对应的应用
	app := FindApplicationByPort(apps, port)
	if app == nil {
		errMsg := fmt.Sprintf("Application with port %d not found", port)
		log.Printf(errMsg)
		http.Error(w, errMsg, http.StatusBadRequest)
		return
	}

	// 获取日志文件路径
	logPath, err := DownloadApplicationLog(app)
	if err != nil {
		log.Printf("Failed to download application log: %v\n", err)
		http.Error(w, fmt.Sprintf("Failed to download application log: %v", err), http.StatusInternalServerError)
		return
	}

	// 设置响应头以触发下载
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s_nohup.out\"", app.JarName))
	w.Header().Set("Content-Type", "application/octet-stream")

	// 读取并发送日志文件内容
	http.ServeFile(w, r, logPath)
}
